#include "song.h"
#include "tinyxml.h"
using namespace std;

note::note() {
  // empty constructor
  rest = false;
}

note::note(wxString thepitch, wxByte thestring, wxByte thefret, wxByte thetype, int thesharp, int theflat,
           wxByte theoctave, int meterbottom, int tempo) {
  // constructor
  status = 0;
  flat = theflat;
  sharp = thesharp;
  octave = theoctave;
  if(thepitch == _("A")) {
    pitch = 0;
  } else if(thepitch == _("B")) {
    pitch = 1;
  } else if(thepitch == _("C")) {
    pitch = 2;
  } else if(thepitch == _("D")) {
    pitch = 3;
  } else if(thepitch == _("E")) {
    pitch = 4;
  } else if(thepitch == _("F")) {
    pitch = 5;
  } else if(thepitch == _("G")) {
    pitch = 6;
  } else {
    // default
    pitch = 0;
  }
  if(octave > 4) {
    upsideDown = true;
  } else {
    upsideDown = false;
  }
  pitchString = thepitch;
  string    = thestring;
  fret      = thefret;
  type      = thetype;
  rest      = false;
  calculateKeyNumber();
  calculateFrequency();
  calculateTime(meterbottom, tempo);
}

note::note(wxByte thetype, int meterbottom, int tempo) {
  type      = thetype;
  rest      = true;
  flat      = 0;
  sharp     = 0;
  octave    = 4;
  pitch     = 6;
  keyNumber = 0;
  frequency = 0.0f;
  status    = 0;
  string    = 0;
  fret      = 0;
  calculateTime(meterbottom, tempo);
}

void note::calculateFrequency() {
  // calculate the frequency, needs a key number
  if(keyNumber > 0) {
    frequency = 27.5 * pow(2.0f, (float)(keyNumber - 1) / 12);
  } else {
    frequency = 0.0f;
  }
}

// calculates the keynumber of this tone, ranging from 1 to 88
void note::calculateKeyNumber() {
  keyNumber = (octave - 2 + (pitch < 2 ? 1 : 0)) * 12;
  // handle the sharps and flats
  switch(pitch) {
    case 0: // A
      if(flat)        keyNumber += 0;
      else if(sharp)  keyNumber += 2;
      else            keyNumber += 1;
      break;
    case 1: // B
      if(flat)        keyNumber += 2;
      else            keyNumber += 3;
      break;
    case 2: // C
      if(sharp)       keyNumber += 5;
      else            keyNumber += 4;
      break;
    case 3: // D
      if(flat)        keyNumber += 5;
      else if(sharp)  keyNumber += 7;
      else            keyNumber += 6;
      break;
    case 4: // E
      if(flat)        keyNumber += 7;
      else            keyNumber += 8;
      break;
    case 5: // F
      if(sharp)  keyNumber += 10;
      else            keyNumber += 9;
      break;
    case 6: // G
      if(flat)        keyNumber += 10;
      else if(sharp)  keyNumber += 12;
      else            keyNumber += 11;
      break;
  }
}

// calculates the time of the note, in seconds/1000
void note::calculateTime(int meterbottom, int tempo) {
  float timePerNote = (float)60000 / tempo;
  time = (int)(timePerNote * ((float)meterbottom / type));
}

song::song() {
  // empty constructor
  speed = 0;
}

void song::loadSong(wxString songPath) {
  TiXmlDocument doc(songPath.mb_str(wxConvUTF8));
  if(doc.LoadFile()) {
    TiXmlHandle docHandle(&doc);
    TiXmlElement* tmpelement = docHandle.FirstChild("song").Element();
    title = wxString::FromAscii(tmpelement->Attribute("title"));
    artist = wxString::FromAscii(tmpelement->Attribute("artist"));
    tmpelement->QueryIntAttribute("tempo", &tempo);
    tmpelement->QueryIntAttribute("metertop", &metertop);
    tmpelement->QueryIntAttribute("meterbottom", &meterbottom);

    // load the notes
    totalLength = 0;
    for(tmpelement = docHandle.FirstChild("song").FirstChildElement().Element();
        tmpelement;
        tmpelement = tmpelement->NextSiblingElement()) {
      //wxMessageBox(wxString::FromAscii(tmpelement->Value()));
      if(wxString::FromAscii(tmpelement->Value()) == _("note")) {
        // a normal note
        notes.push_back(new note(wxString::FromAscii(tmpelement->Attribute("pitch")),
                                 wxAtoi(wxString::FromAscii(tmpelement->Attribute("string"))),
                                 wxAtoi(wxString::FromAscii(tmpelement->Attribute("fret"))),
                                 wxAtoi(wxString::FromAscii(tmpelement->Attribute("type"))),
                                 wxAtoi(wxString::FromAscii(tmpelement->Attribute("sharp"))),
                                 wxAtoi(wxString::FromAscii(tmpelement->Attribute("flat"))),
                                 wxAtoi(wxString::FromAscii(tmpelement->Attribute("octave"))),
                                 meterbottom, tempo
                                 ));
      } else if(wxString::FromAscii(tmpelement->Value()) == _("rest")) {
        // it is a rest note
        notes.push_back(new note(wxAtoi(wxString::FromAscii(tmpelement->Attribute("type"))), meterbottom, tempo));
      } else {
        // error
        wxMessageBox(_("Illegal syntax in XML-file"), _("Error"));
        return;
      }
      totalLength += (float)meterbottom / notes[notes.size() - 1]->type;
    }

  } else {
    wxMessageBox(_("Error while opening file"), _("Error"));
  }
}

void song::reset() {
  artist = wxEmptyString;
  title = wxEmptyString;
  tempo = metertop = meterbottom = 0;
  notes.clear();
}
